﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Xml;
using System.Xml.Linq;

namespace ComTools.File
{
    /// <summary>
    /// XML转换工具类
    /// *功 能： 该类主要用于对象转 XML String
    /// *将实体集合转为XMLDocument
    /// *将实体集合转换为XDocument（支持linq for xml）
    /// *将集合转换为XElement（支持linq for xml）
    /// *将实体转换为XML String
    /// *将实体转换成XElement
    /// *根据类型转换XElement
    /// </summary>
    public static class XmlConverter
    {
        /// <summary>
        /// 实体集合转化成标准XML
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="entities">实体集合</param>
        /// <param name="rootName">根节点名字</param>
        /// <returns>生成的XML字符串</returns>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="Exception"></exception>
        [MethodImpl(MethodImplOptions.NoInlining)]
        public static string ObjectListToXml<T>(this IList<T> entities, string rootName = "") where T : new()
        {
            try
            {
                if (entities == null || entities.Count == 0) throw new ArgumentNullException("entities");

                XElement element = ToXElement<T>(entities, rootName);

                return element != null ? element.ToString() : string.Empty;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 实体集合转为XML文档
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="entities">实体集合</param>
        /// <param name="rootName">根节点名称</param>
        /// <returns>转换的XMLDocuemtn</returns>
        [MethodImpl(MethodImplOptions.NoInlining)]
        public static XmlDocument ToXmlDocument<T>(IList<T> entities, string rootName = "") where T : new()
        {
            if (entities == null || entities.Count == 0)
            {
                return null;
            }

            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.LoadXml(ObjectListToXml<T>(entities, rootName));

            return xmlDocument;
        }

        /// <summary>
        /// 将实体集合转换为XDocument（支持linq for xml）
        /// </summary>
        /// <typeparam name="T">转换类型</typeparam>
        /// <param name="entities">实体集合</param>
        /// <param name="rootName">根节点名称</param>
        /// <returns>转换的XDocument</returns>
        [MethodImpl(MethodImplOptions.NoInlining)]
        public static XDocument ToXDocument<T>(this IList<T> entities, string rootName = "") where T : new()
        {
            if (entities == null || entities.Count == 0)
            {
                return null;
            }
            return XDocument.Parse(ObjectListToXml<T>(entities, rootName));
        }

        /// <summary>
        /// 将集合转换为XElement（支持linq for xml）
        /// </summary>
        /// <typeparam name="T">转换类型</typeparam>
        /// <param name="entities">实体集合</param>
        /// <param name="rootName">根节点名称</param>
        /// <returns>转换的XElement</returns>
        [MethodImpl(MethodImplOptions.NoInlining)]
        public static XElement ToXElement<T>(this IList<T> entities, string rootName = "") where T : new()
        {
            if (entities == null || entities.Count == 0)
            {
                return null;
            }

            if (string.IsNullOrWhiteSpace(rootName))
            {
                //rootName = typeof(T).Name + XmlResource.XmlRootNameSuffix;
                rootName = typeof(T).Name;
            }

            XElement element = new XElement(rootName);

            foreach (T entity in entities)
            {
                element.Add(ToXElement<T>(entity));
            }

            return element;
        }

        /// <summary>
        /// 将实体转换为XML String
        /// </summary>
        /// <typeparam name="T">转换类型</typeparam>
        /// <param name="entity">要转换的实体</param>
        /// <returns>转换的XElement</returns>
        [MethodImpl(MethodImplOptions.NoInlining)]
        public static string ToXml<T>(this T entity) where T : new()
        {
            if (entity == null)
            {
                return string.Empty;
            }

            XElement element = ToXElement<T>(entity);

            return element.ToString();
        }

        /// <summary>
        /// 将实体转换成XElement
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="entity">对象实体</param>
        /// <returns>转换的XElement</returns>
        [MethodImpl(MethodImplOptions.NoInlining)]
        public static XElement ToXElement<T>(this T entity) where T : new()
        {
            if (entity == null)
            {
                return null;
            }

            XElement element = new XElement(typeof(T).Name);
            PropertyInfo[] properties = typeof(T).GetProperties();
            XElement innerElement = null;
            object propertyValue = null;

            foreach (PropertyInfo property in properties)
            {
                propertyValue = property.GetValue(entity, null);
                innerElement = new XElement(property.Name, propertyValue);
                element.Add(innerElement);
            }

            return element;
        }

        /// <summary>
        /// 根据类型转换XElement
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns>转换的XElement</returns>
        [MethodImpl(MethodImplOptions.NoInlining)]
        public static XElement ToXElement(this Type type)
        {
            if (type == null)
            {
                return null;
            }

            XElement element = new XElement(type.Name);
            PropertyInfo[] properties = type.GetProperties();
            XElement innerElement = null;

            foreach (PropertyInfo property in properties)
            {
                innerElement = new XElement(property.Name, null);
                element.Add(innerElement);
            }

            return element;
        }
    }
}
